/**
 *  JSimProd - Java simulation code for production processes
 *  Copyleft Jorge Mira Yagüe <jorge.mira.yague@gmail.com>
 *  Universidad de Alicante 2009
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package lib.model;

import lib.xml.XMLizable;
import lib.exceptions.XMLParsingException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import lib.xml.FactoryModelReader;
import org.xml.sax.SAXException;

/**
 * FactoryModel is a class which represents the factory where the simulation is
 * done. It has a collection of stations which are capable to do some tasks, and
 * another collection of item categories, which describe how to produce the
 * items that the factory makes.
 * @see Station
 * @see ItemCategory
 * @author Jorge Mira Yagüe
 */
public class FactoryModel implements XMLizable {

    private String name;
    private Calendar whenModified;
    Map<String, Station> stations;
    Map<String, ItemCategory> categories;

    /**
     * Builds an empty factory model
     */
    public FactoryModel() {
        name = "";
    }

    /**
     * Class constructor
     * @param name the name of the factory model
     */
    public FactoryModel(String name) {
        this.name = name;
        stations = new HashMap<String, Station>();
        categories = new HashMap<String, ItemCategory>();
    }

    public String getName() {
        return name;
    }

    public Calendar getWhenModified() {
        return whenModified;
    }

    public void setWhenModified(Calendar whenModified) {
        this.whenModified = whenModified;
    }

    /**
     * Adds a station to the factory model
     * @param station the station to be added
     */
    public void addStation(Station station) {
        stations.put(station.getName(), station);
    }

    /**
     * Removes a station from the factory
     * @param name the station to be removed
     */
    public void removeStation(String name) {
        stations.remove(name);
    }

    /**
     * Adds an item category to the station
     * @param category the item category to be added
     */
    public void addItemCategory(ItemCategory category) {
        categories.put(category.getName(), category);
    }

    /**
     * Removes a item category from the factory
     * @param name the item category to be removed
     */
    public void removeItemCategory(String name) {
        categories.remove(name);
    }

    /**
     * Returns the station with the name specified, or null if the station
     * doesn't exist
     * @param name the name of the station to get
     * @return the station with the name specified, or null if the station
     * doesn't exist
     */
    public Station getStation(String name) {
        return stations.get(name);
    }

    /**
     * Returns the item category with the name specified, or null if the
     * item category doesn't exist
     * @param name the name of the item category to get
     * @return the item category with the name specified, or null if the
     * item category doesn't exist
     */
    public ItemCategory getItemCategory(String name) {
        return categories.get(name);
    }

    public Map<String, Station> getStations() {
        return stations;
    }

    public Map<String, ItemCategory> getItemCategories() {
        return categories;
    }

    /**
     * Saves the factory model using the name of the factory model for the file
     * name, appending it the date and the .cfg extension
     * @throws java.io.FileNotFoundException if can't create the file
     * @throws IOException when an error ocurred during I/O
     */
    public void Save() throws FileNotFoundException, IOException {
        SaveAs(new File(name + ".xml"));
    }

    /**
     * Saves the factory model using the specified value for the file name,
     * appending it the date and the .cfg extension
     * @param file the name for the file to save the factory model
     * @throws java.io.FileNotFoundException if can't create the file
     * @throws IOException when an error ocurred during I/O
     */
    public void SaveAs(File file) throws FileNotFoundException, IOException {
        if (!file.getName().endsWith(".xml")) {
            file = new File(file.getPath() + ".xml");
        }

        if (file.exists()) {
            Date date = new Date(file.lastModified());
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmm");
            String fileName = file.getPath();
            String backupName = file.getPath().substring(0, file.getPath().length() - 4) +
                    "-v" + format.format(date) + ".xml";
            file.renameTo(new File(backupName));
            file = new File(fileName);
        }
        whenModified = Calendar.getInstance();
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(toXML().getBytes());
        fos.close();
    }

    /**
     * Loads a factory model into the object from the file specified
     * @param file the file with the factory model
     * @throws java.io.FileNotFoundException if the file doesn't exists
     * @throws XMLParsingException if occurs an error parsing the XML file
     */
    public static FactoryModel Load(File file) throws FileNotFoundException,
            XMLParsingException,
            IOException {
        try {
            FactoryModelReader fmr = new FactoryModelReader();
            return fmr.getFMFromXML(file);
        } catch (SAXException saxe) {
            throw new XMLParsingException(file.getName());
        }
    }

    public String toXML() {
        Iterator iterator;
        if (whenModified == null) {
            whenModified = Calendar.getInstance();
        }
        String result = "<FactoryModel ";
        result += "name=\"" + name + "\" ";
        result += "whenModified=\"" + whenModified.getTimeInMillis() + "\" ";
        result += ">\n";
        if (categories != null) {
            iterator = categories.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry e = (Map.Entry) iterator.next();
                result += ((ItemCategory) e.getValue()).toXML();
            }
        }
        if (stations != null) {
            iterator = stations.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry e = (Map.Entry) iterator.next();
                result += ((Station) e.getValue()).toXML();
            }
        }
        result += "</FactoryModel>\n";
        return result;
    }
}
